package config;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

@SuppressWarnings("all")
public class RequestMappingHandlerMappingCustom extends RequestMappingHandlerMapping
{

	private String basePackage;

	public String getBasePackage()
	{
		return basePackage;
	}

	public void setBasePackage(String basePackage)
	{
		this.basePackage = basePackage;
	}

	@Override
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType)
	{
		RequestMappingInfo info = createRequestMappingInfo(method);
		if (info != null)
		{
			RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
			if (typeInfo != null)
			{
				info = typeInfo.combine(info);
			}
		}
		return info;
	}

	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element)
	{
		RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);

		if (requestMapping == null)
		{
			if (element instanceof Method)
			{
				if (Modifier.PRIVATE == ((Method) element).getModifiers())
				{
					return null;
				}
			}
			requestMapping = new MyRequestMapping(element);
		}
		else if (requestMapping.value().length == 0)
		{
			requestMapping = new MyRequestMapping(element, requestMapping);
		}

		RequestCondition<?> condition = (element instanceof Class<?> ? getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
		return createRequestMappingInfo(requestMapping, condition);
	}

	class MyRequestMapping implements RequestMapping
	{
		private String prefix = "";

		private AnnotatedElement element;

		private RequestMapping requestMapping;

		private String[] defaultArr = {};

		public MyRequestMapping(AnnotatedElement element)
		{
			this.element = element;
		}

		public MyRequestMapping(AnnotatedElement element, RequestMapping requestMapping)
		{
			this.element = element;
			this.requestMapping = requestMapping;
		}

		private String getNameSpace(String packageName, String className)
		{
			packageName = packageName.replaceFirst(basePackage, "").replace('.', '/').toLowerCase();
			className = camelToUnderline(className);
			return packageName + "/" + className;
		}

		public String camelToUnderline(String param)
		{
			if (param == null || "".equals(param.trim()))
			{
				return "";
			}
			int len = param.length();
			StringBuilder sb = new StringBuilder(len);
			for (int i = 0; i < len; i++)
			{
				char c = param.charAt(i);
				if (Character.isUpperCase(c))
				{
					sb.append("-");
					sb.append(Character.toLowerCase(c));
				}
				else
				{
					sb.append(c);
				}
			}
			return sb.toString().replaceFirst("-", "");
		}

		@Override
		public Class<? extends Annotation> annotationType()
		{
			return (requestMapping == null) ? null : requestMapping.annotationType();
		}

		@Override
		public String name()
		{
			return (requestMapping == null) ? "" : requestMapping.name();
		}

		@Override
		public String[] value()
		{
			if (requestMapping == null || requestMapping.value().length == 0)
			{
				if (element instanceof Class<?>)
				{
					Class<?> c = (Class<?>) element;
					return new String[] { getNameSpace(c.getPackage().getName(), c.getSimpleName().replaceAll("Controller$", "")) };
				}
				else
				{
					String methodName = ((Method) element).getName();
					if (!methodName.equals("execute"))
					{
						return new String[] { prefix + methodName };
					}
					else
					{
						return new String[] { prefix + methodName, "" };
					}
				}
			}
			return requestMapping.value();

		}

		@Override
		public String[] path()
		{
			return value();
		}

		@Override
		public RequestMethod[] method()
		{
			return requestMapping == null ? new RequestMethod[] {} : requestMapping.method();
		}

		@Override
		public String[] params()
		{
			return requestMapping == null ? defaultArr : requestMapping.params();
		}

		@Override
		public String[] headers()
		{
			return requestMapping == null ? defaultArr : requestMapping.headers();
		}

		@Override
		public String[] consumes()
		{
			return requestMapping == null ? defaultArr : requestMapping.consumes();
		}

		@Override
		public String[] produces()
		{
			return requestMapping == null ? defaultArr : requestMapping.produces();
		}

	}

}
